package day15;

import day14.Client;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

//用户系统
public class AccountSystem {
    static ScheduledExecutorService ses=
            Executors.newScheduledThreadPool(10);//可定长周期线程池
    static List<Account> list = new ArrayList<Account>();
    static Scanner sc = new Scanner(System.in);
    public static void main(String[] args) {
        one();
//        System.out.println(md5("123"));
//        System.out.println(md5("abc"));
    }
    public static void one() {
        while (true){
            System.out.println("xxxXX系统xxx");
            System.out.println("1.登录");
            System.out.println("2.注册");
            System.out.println("3.退出");
            System.out.println("*******请输入编号******");
            int choice = sc.nextInt();
            switch (choice) {
                case 1:login();break;
                case 2:reg();break;
                case 3:return;
            }
        }
    }
    //如果第一次登录成功  可以记录缓存(登录成功的记录)
    //如果下一次再登录  还是相同的账号(可以不输入密码直接免登录)
    //缓存的记录  一直在30秒失效
    public static void login() {
        System.out.println("请输入账号");
        String account=sc.next();
        //验证是否登陆过===》two()
        Account acc=checkCookie(account);
        if(acc!=null){
            two(acc);return;
        }
        System.out.println("请输入密码");
        String password=sc.next();
        for (Account a:list){
            if (account.equals(a.username)&&
                    password.equals(a.password)){
                System.out.println("是否保存本地缓存y/n,30s内免登录");
                String yn=sc.next();
                if ("y".equals(yn)){
                    addCookie(a);
                    //可周期定长线程池 30s首次延迟时间
                    ses.schedule(()->{
                        removeCookie(account);
                    },30, TimeUnit.SECONDS);
                }
                two(a);
                return;
            }else {
                System.out.println("账号或密码错误");
            }
        }
    }
    public static void removeCookie(String account){
        File f=new File("d:\\io\\cookies"+account+".txt");
        if(f.delete()) System.out.println("缓存失效了");
    }
    public static void addCookie(Account a){
        try (FileOutputStream fos=
                     new FileOutputStream("d://io//cookies-"+a.username+".txt")
        ){
            fos.write(md5(a.username).getBytes());
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static String md5(String msg) {
        StringBuilder hexString=null;
        try {
// 获取 MessageDigest 类的实例，指定算法为 MD5
            MessageDigest digest = MessageDigest.getInstance("MD5");
// 对字符串进行加密
            byte[] encodedHash = digest.digest(msg.getBytes());
// 将加密后的字节数组转换为十六进制字符串
            hexString = new StringBuilder();
            for (byte b : encodedHash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hexString.toString();
    }
    public static Account checkCookie(String account){
        try (BufferedReader br=new BufferedReader(
                new InputStreamReader(
                        new FileInputStream("d://io//cookies-"+account+".txt")))) {
            String msg= br.readLine();
            //将账号加密后和之前保存的加密信息  匹配是否一样
            if (msg!=null&&msg.equals(md5(account))){
                for (Account a:list){
                    if (account.equals(a.username)){
                        return a;
                    }
                }
            }
        }catch (FileNotFoundException e){
            System.out.println("首次登录");
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }
    public static void reg() {
        System.out.println("请输入账号：");
        String account = sc.next();
        System.out.println("请输入密码：");
        String password = sc.next();
        Account a= new Account(account, password);
        list.add(a);
        //序列化
    }
    //登录成功会进入二级菜单连接Socket服务端
    public static void two(Account a){
        System.out.println(a.username+"登录成功");
        Socket client= null;
        try {
            client = new Socket("127.0.0.1",9999);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //存储客户端对象
        //AccountServer.map.put(a.username,client);
        //读取服务端写的数据(怎么读不能影响主程序 所以是客户端线程)
        ClientThread ct=new ClientThread(client);
        ct.start();
        while (true){
            System.out.println("1.聊天功能");//进行私聊
            System.out.println("2.退出登录");
            System.out.println("0.返回上级");
            int choice = sc.nextInt();
            switch (choice) {
                case 1: chat(a,client);break;
                case 2: removeCookie(a.username);
                        //客户端线程要停 删除socket对象
                        ct.b=true;
                        AccountServer.map.remove(a.username);
                        try {
                        client.close(); // 关闭Socket
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                case 0:return;
            }
        }
    }
    //进行私聊 创建输出流 去写 给发送方
    //比那个且要告诉服务端 发送方和接收方
    public static void chat(Account a,Socket client){
        System.out.println("请输入对方的账号:");
        String to=sc.next();
        try {
            OutputStream os=client.getOutputStream();//写数据
            //第一次给服务端写入时 要告诉服务端谁是发送方谁是接收方
            os.write((a.username+"=>"+to+"\n").getBytes());
            //开始聊天
            while (true){
                System.out.println("请输入你要向"+to+"发送的消息,esc退出");
                String msg=sc.nextLine();
                if("esc".equals(msg)){
                    //退出聊天 只是不想发消息 没有退出登录 并不影响接收消息
                    //os.write((a.username+"说:esc\n").getBytes());
                    //break;
                    return;
                }
                os.write((a.username+"说"+msg+"\n").getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //client.getOutputStream();
    }
}
class Account{
    String username;
    String password;
    public Account(String username, String password) {
        this.username = username;
        this.password = password;
    }
}
//Socket服务端 和主程序独立 而且是先开好的
class AccountServer{
    //key账号 value对应的客户端对象
    static Map<String,Socket> map=new HashMap<>();
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(9999);
        System.out.println("服务器启动成功");
        while (true){
            Socket client=server.accept();
            //线程
            new ServerThread(client).start();
        }
    }
}
class ServerThread extends Thread{
    Socket client;
    public ServerThread(Socket client){
        this.client=client;
    }
    //写什么逻辑:先接收数据 (得到发送方和接收方)
    //发送方进行读取 对接收方进行写入
    //如果对方不在线 可以实现离线消息存储 也可以不发送消息
    public void run() {
        try(BufferedReader br=new BufferedReader(
                new InputStreamReader(client.getInputStream()))){
            String fromAndTo=br.readLine();//a(发)=>b(收)
            //fromTo[0]=发送方 fromTO[1]=接收方
            String[] fromTo=fromAndTo.split("=>");
            AccountServer.map.put(fromTo[0],client);
            while (true){
                //开始读取数据
                String msg= br.readLine();
//                if(msg==null||msg.equals("esc")){//是否要退出 目的是为了结束线程 不需要再给别人发了
//                    return;
//                }
                if(AccountServer.map.containsKey(fromTo[1])){//在线
                    //给接收方直接写入数据
                    Socket toClient=AccountServer.map.get(fromTo[1]);
                    OutputStream os=toClient.getOutputStream();
                    os.write((msg+"\n").getBytes());
                }else{//不在线
                    //给发送方返回一个结果
                    OutputStream os=client.getOutputStream();
                    os.write((fromTo[1]+"不在线哦\n").getBytes());
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
//客户端线程
class ClientThread extends Thread{
    Socket client;
    volatile boolean b;
    public ClientThread(Socket client) {
        this.client = client;
    }
    public void run() {
        try(BufferedReader br=new BufferedReader(
                new InputStreamReader(client.getInputStream()))) {
            while (!b){  //什么时候结束线程
                String msg=br.readLine();
                if(msg!=null&&!msg.equals("")){
                    System.out.println(msg);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}